﻿// ## 2024/01/27 # 江东新风 # 初次编写,所有ai的部队任务均在此执行，包括玩家委任部队 ##
namespace AI_RUN_UNIT_ORDER
{

	class pos_score
	{
		pk::point pos;
		int score;

	};

	pos_score pos_score_;

	class Main
	{
		pk::c_bool 调试模式 = pk::c_bool(false);
		Main()
		{
			pk::set_func(262, pk::func262_t(callback));
			pk::bind(260, pk::trigger260_t(AI执行任务_262_打印));
		}

		void AI执行任务_262_打印()
		{
			ImGui::Checkbox("调试模式", 调试模式);
		}

		pk::list<pk::unit @> list_candidate_unit;
		pk::list<pk::building @> list_candidate_building;
		pk::list<pk::unit @> list_ally_unit;
		pk::unit @src_unit;


		//不是部队数。而且在超级难度或者目标是玩家时，此设定无效
		bool callback(pk::unit_manager@ unit_mgr, pk::unit@ unit)
		{
			// if (unit.get_force_id() == 11)
			// 	pk::trace(pk::format("{}:{},兵器:{},移动力：{}",pk::decode(pk::get_name(unit)),unit.order, unit.weapon, unit.attr.stat[部队能力_移动]));

			switch (unit.order)
			{
				case 部队任务_移动:
					return unit_mgr.run_move_order();
				case 部队任务_设置:
					//if (true) return new_building_order(unit_mgr, unit);
					return unit_mgr.run_build_order();
				case 部队任务_攻击:
					return unit_mgr.run_attack_order();//想要替换部队执行攻击任务的ai，就把此处的函数替换成你新写的函数就好
				case 部队任务_撤退:
					return unit_mgr.run_retreat_order();
				case 部队任务_拦截:
					return unit_mgr.run_expel_order();
				case 部队任务_攻城:
					return unit_mgr.run_siege_order();//注意原版此ai为空，故永远返回false，可以新写一个替换
				case 部队任务_修复:
					return unit_mgr.run_repair_order();
				case 部队任务_征服:
					if (pk::get_building_id(unit.pos) == pk::get_person(unit.leader).service) //征服部队在自己据点的时候
						return new_conquer_order(unit_mgr, unit);
						//return unit_mgr.run_attack_order();
					else
						return unit_mgr.run_subjugate_order();
				case 部队任务_补给:
					return unit_mgr.run_supply_order();
				case 部队任务_歼灭:
					return unit_mgr.run_annihilate_order();
				case 部队任务_追随:
					break;//追随只有玩家有效，貌似在发布命令时就执行了？没看到对应ai
				default:
					break;
			}

			////关于pk::action_info的范例
			////结构形式可以参考pk::damage_info或者pk::point
			//pk::action_info info();
			//info.type = 5;//1 攻击, 2 齐攻, 3 单挑, 4 战法, 5计略, 6 建造 7 修复
			//info.move_pos = pk::point(1,1);//即将要移动到的坐标，需要确保能移动到
			//info.target_pos = pk::point(2,2);//要执行动作对象的坐标，如果攻击，就是攻击对象的坐标，建造，就是要建造建筑物的坐标
			//info.action_id = 计略_扰乱;//可以是tactics_id, facility_id, strategy_id，根据info.type决定，如攻击，齐攻，单挑就是-1，如战法，就是战法id，计略，就是计略id，建造，就是要建造设施的id(修复时不需要id)
			//info.score = 10000;//对应动作的打分，所以可以建一个数组，储存多个action_info,最后比较得分来随机选择得分高的action_info去执行
			//info.chance = 50;//执行对应动作的成功率，如计略就是计略成功率，战法就是战法成功率，单挑就是单挑成功率
			////info.chance = cast<pk::func206_t>(pk::get_func(206))(unit, info.move_pos, info.target_pos, 计略_扰乱).first;//执行妙计_大混乱成功率的写法
			//unit_mgr.conduct_action(info);
			return false;
		}

		//处于己方领地的征服任务部队逻辑重置(暂时简单写逻辑)
		bool new_building_order(pk::unit_manager@ unit_mgr, pk::unit@ unit)
		{
			if (true)
			{
				pos_score pos_info;
				p_score_arr.resize(0);
				pk::array<pk::point> arr_range = pk::get_movable_pos(unit);
				pk::array<pk::point> path_range = pk::get_path(unit, unit.pos, get_empty_pos(unit.target_pos, 1, 1));
				if (arr_range.length == 0) return false; //暂时什么都不做

				if (path_range.length > 0)
				{
					for (int i = 0; i < int(arr_range.length); i++)
					{

						if (path_range.find(arr_range[i]) < 0) continue;
						pk::hex @hex = pk::get_hex(arr_range[i]);
						if (hex.has_building or hex.has_unit)  continue;

						pos_info.pos = arr_range[i];
						pos_info.score = path_range.find(arr_range[i]);
						//pk::trace(pk::format("{}:目标坐标为{},{},搜索可用坐标{},{},打分{}", pk::decode(pk::get_name(unit)), target_building.pos.x, target_building.pos.y, arr_range[i].x, arr_range[i].y, pos_info.score));

						p_score_arr.insertLast(pos_info);
					}
				}
				if (p_score_arr.length > 0)
				{

					p_score_arr.sort(function(a, b) {
						return a.score > b.score;
					});

					pk::trace(pk::format("{}:func262移动到{},{}", pk::decode(pk::get_name(unit)), p_score_arr[0].pos.x, p_score_arr[0].pos.y));

					pk::action_info info = pk::action_info();
					info.type = 0;//1 攻击, 2 齐攻, 3 单挑, 4 战法, 5计略, 6 建造 7 修复
					info.move_pos = p_score_arr[0].pos;//即将要移动到的坐标，需要确保能移动到
					//info.target_pos = unit.target_pos;//要执行动作对象的坐标，如果攻击，就是攻击对象的坐标，建造，就是要建造建筑物的坐标
					//info.action_id = unit.target;//可以是tactics_id, facility_id, strategy_id，根据info.type决定，如攻击，齐攻，单挑就是-1，如战法，就是战法id，计略，就是计略id，建造，就是要建造设施的id(修复时不需要id)
					//info.score = 10000;//对应动作的打分，所以可以建一个数组，储存多个action_info,最后比较得分来随机选择得分高的action_info去执行
					//info.chance = 50;//执行对应动作的成功率，如计略就是计略成功率，战法就是战法成功率，单挑就是单挑成功率
					//info.chance = cast<pk::func206_t>(pk::get_func(206))(unit, info.move_pos, info.target_pos, 计略_扰乱).first;//执行妙计_大混乱成功率的写法
					if (调试模式.v)pk::trace(pk::format("{}:移动到{},{},部队目标{}", pk::decode(pk::get_name(unit)), p_score_arr[0].pos.x, p_score_arr[0].pos.y, unit.status));
					pk::get_movable_pos(unit, true);
					pk::conduct_action(info);

					return true;

				}

				else
				{

					pk::action_info info = pk::action_info();
					info.type = 6;//1 攻击, 2 齐攻, 3 单挑, 4 战法, 5计略, 6 建造 7 修复
					info.move_pos = unit.pos;//即将要移动到的坐标，需要确保能移动到
					info.target_pos = unit.target_pos;//要执行动作对象的坐标，如果攻击，就是攻击对象的坐标，建造，就是要建造建筑物的坐标
					info.action_id = 设施_军乐台;//可以是tactics_id, facility_id, strategy_id，根据info.type决定，如攻击，齐攻，单挑就是-1，如战法，就是战法id，计略，就是计略id，建造，就是要建造设施的id(修复时不需要id)
					//info.score = 10000;//对应动作的打分，所以可以建一个数组，储存多个action_info,最后比较得分来随机选择得分高的action_info去执行
					//info.chance = 50;//执行对应动作的成功率，如计略就是计略成功率，战法就是战法成功率，单挑就是单挑成功率
					//info.chance = cast<pk::func206_t>(pk::get_func(206))(unit, info.move_pos, info.target_pos, 计略_扰乱).first;//执行妙计_大混乱成功率的写法
					pk::trace(pk::format("{}:移动到{},{},部队目标{}", pk::decode(pk::get_name(unit)), unit.pos.x, unit.pos.y, unit.status));
					pk::get_movable_pos(unit, true);
					pk::conduct_action(info);
					return true;
				}
			}

			return false;
		}

		array<pos_score> p_score_arr;

		//处于己方领地的征服任务部队逻辑重置(暂时简单写逻辑)
		bool new_conquer_order(pk::unit_manager@ unit_mgr, pk::unit@ unit)
		{
			pos_score pos_info;
			p_score_arr.resize(0);
			pk::building @target_building = pk::get_building(unit.target);

			//如果附近(己方领域)存在敌军部队,且能攻击到
			@src_unit = @unit;
			get_list_candidate_unit(unit);
			int target_count_unit = list_candidate_unit.count; // 候选目标部队数量
			if (target_count_unit > 0)
			{
				list_candidate_unit.sort(function(a, b) {
					float stat_a = pk::get_distance(main.src_unit.pos, a.pos);
					float stat_b = pk::get_distance(main.src_unit.pos, b.pos);
					return (stat_a < stat_b);
				});
				pk::int_int atk_range = get_atk_range(unit);

				pk::action_info info = pk::action_info();
				info.type = 1;//1 攻击, 2 齐攻, 3 单挑, 4 战法, 5计略, 6 建造 7 修复
				info.move_pos = get_movable_empty_pos(unit, list_candidate_unit[0].pos, 0, atk_range.second);//即将要移动到的坐标，需要确保能移动到
				if (unit.weapon == 兵器_弩 or unit.weapon == 兵器_井阑)
					info.move_pos = get_movable_empty_pos(unit, list_candidate_unit[0].pos, 1, atk_range.second);//即将要移动到的坐标，需要确保能移动到

				info.target_pos = list_candidate_unit[0].pos;//要执行动作对象的坐标，如果攻击，就是攻击对象的坐标，建造，就是要建造建筑物的坐标
				info.action_id = -1;//可以是tactics_id, facility_id, strategy_id，根据info.type决定，如攻击，齐攻，单挑就是-1，如战法，就是战法id，计略，就是计略id，建造，就是要建造设施的id(修复时不需要id)
				info.score = 10000;//对应动作的打分，所以可以建一个数组，储存多个action_info,最后比较得分来随机选择得分高的action_info去执行
				info.chance = 50;//执行对应动作的成功率，如计略就是计略成功率，战法就是战法成功率，单挑就是单挑成功率
				//info.chance = cast<pk::func206_t>(pk::get_func(206))(unit, info.move_pos, info.target_pos, 计略_扰乱).first;//执行妙计_大混乱成功率的写法
				if (调试模式.v)pk::trace(pk::format("{}:执行攻击部队{},{}", pk::decode(pk::get_name(unit)), info.target_pos.x, info.target_pos.y));
				pk::conduct_action(info);
				return true;

			}

			//如果附近(己方领域)存在敌军建筑(暂时简单写逻辑)
			get_list_candidate_building(unit);
			int target_count_building = list_candidate_building.count; // 候选目标部队数量
			if (target_count_building > 0)
			{
				list_candidate_building.sort(function(a, b) {
					float stat_a = pk::get_distance(main.src_unit.pos, a.pos);
					float stat_b = pk::get_distance(main.src_unit.pos, b.pos);
					return (stat_a < stat_b);
				});
				pk::int_int atk_range = get_atk_range(unit);

				pk::action_info info = pk::action_info();
				info.type = 1;//1 攻击, 2 齐攻, 3 单挑, 4 战法, 5计略, 6 建造 7 修复
				info.move_pos = get_movable_empty_pos(unit, list_candidate_building[0].pos, 0, atk_range.second);//即将要移动到的坐标，需要确保能移动到
				if (unit.weapon == 兵器_弩 or unit.weapon == 兵器_井阑)
					info.move_pos = get_movable_empty_pos(unit, list_candidate_building[0].pos, 1, atk_range.second);//即将要移动到的坐标，需要确保能移动到

				info.target_pos = list_candidate_building[0].pos;//要执行动作对象的坐标，如果攻击，就是攻击对象的坐标，建造，就是要建造建筑物的坐标
				info.action_id = -1;//可以是tactics_id, facility_id, strategy_id，根据info.type决定，如攻击，齐攻，单挑就是-1，如战法，就是战法id，计略，就是计略id，建造，就是要建造设施的id(修复时不需要id)
				info.score = 10000;//对应动作的打分，所以可以建一个数组，储存多个action_info,最后比较得分来随机选择得分高的action_info去执行
				info.chance = 50;//执行对应动作的成功率，如计略就是计略成功率，战法就是战法成功率，单挑就是单挑成功率
				//info.chance = cast<pk::func206_t>(pk::get_func(206))(unit, info.move_pos, info.target_pos, 计略_扰乱).first;//执行妙计_大混乱成功率的写法
				if (调试模式.v)pk::trace(pk::format("{}:执行攻击建筑{},{}", pk::decode(pk::get_name(unit)), info.target_pos.x, info.target_pos.y));
				pk::conduct_action(info);
				return true;
			}

			//没有敌军目标就朝着目的地出发
			if (target_count_building == 0 and target_count_unit == 0)
			{
				pk::array<pk::point> arr_range = pk::get_movable_pos(unit);
				pk::array<pk::point> path_range = pk::get_path(unit, unit.pos, target_building.pos);
				pk::array<pk::point> path_range_large;
				if (arr_range.length == 0) return false; //暂时什么都不做

				for (int u = 0; u < int(path_range.length); u++)
				{
					array<pk::point> path_neighbor_arr = pk::range(path_range[u], 1, 1);
					if (pk::get_distance(path_range[u], unit.pos) == 0) continue;
					if (pk::get_distance(path_range[u], unit.pos) >= 10) continue;

					for (int y = 0; y < int(path_neighbor_arr.length); y++)
					{

						int terrain_id = pk::get_hex(path_neighbor_arr[y]).terrain;
						if (!pk::is_valid_terrain_id(terrain_id))
							continue;
						if (!pk::is_enabled_terrain(terrain_id))
							continue;
						if (terrain_id == 地形_浅滩 or terrain_id == 地形_间道 or terrain_id == 地形_栈道)
							continue;

						array<pk::point> path_neighbor_arr2 = pk::range(path_neighbor_arr[y], 1, 1);
						for (int x = 0; x < int(path_neighbor_arr2.length); x++)
						{
							 terrain_id = pk::get_hex(path_neighbor_arr2[x]).terrain;
							if (!pk::is_valid_terrain_id(terrain_id))
								continue;
							if (!pk::is_enabled_terrain(terrain_id))
								continue;
							if (terrain_id == 地形_浅滩 or terrain_id == 地形_间道 or terrain_id == 地形_栈道)
								continue;
							if (path_range_large.find(path_neighbor_arr2[x]) >= 0)
								path_range_large.removeAt(path_range_large.find(path_neighbor_arr2[x]));

							path_range_large.insertLast(path_neighbor_arr2[x]);

						}


						if (path_range_large.find(path_neighbor_arr[y]) >= 0)
							path_range_large.removeAt(path_range_large.find(path_neighbor_arr[y]));

						path_range_large.insertLast(path_neighbor_arr[y]);
						//pk::trace(pk::format("y:{},u:{},{},{}", y, u, path_neighbor_arr[y].x, path_neighbor_arr[y].y));
						if (y == int(path_neighbor_arr.length) - 1) path_range_large.insertLast(path_range[u]);
					}

				}

					// for (int n = 0; n < int(path_range_large.length); n++)
					// {

					// pk::trace(pk::format("n:{},{},{}", n,path_range_large[n].x, path_range_large[n].y));


					// }



				if (path_range.length > 0)
				{
					for (int i = 0; i < int(arr_range.length); i++)
					{

						if (path_range_large.find(arr_range[i]) < 0) continue;
						pk::hex @hex = pk::get_hex(arr_range[i]);
						//if (hex.has_building or hex.has_unit)  continue;

						pos_info.pos = arr_range[i];
						pos_info.score = path_range_large.find(arr_range[i]);
						//pk::trace(pk::format("{}:目标坐标为{},{},搜索可用坐标{},{},打分{}", pk::decode(pk::get_name(unit)), target_building.pos.x, target_building.pos.y, arr_range[i].x, arr_range[i].y, pos_info.score));

						p_score_arr.insertLast(pos_info);
					}
				}

				if (p_score_arr.length == 0) return false; //暂时什么都不做

				p_score_arr.sort(function(a, b) {
					return a.score > b.score;
				});

				pk::point neighbor_pos = p_score_arr[0].pos;

				//pk::trace(pk::format("{}:目标坐标为{},{}", pk::decode(pk::get_name(unit)), p_score_arr[0].pos.x, p_score_arr[0].pos.y));

				//防止目标坐标有问题
				if (pk::get_hex(p_score_arr[0].pos).has_unit or pk::get_hex(p_score_arr[0].pos).has_building)
				{
					neighbor_pos = get_movable_empty_pos(unit, p_score_arr[0].pos, 1, 1);
					//pk::trace(pk::format("{}:目标坐标为{},{}", pk::decode(pk::get_name(unit)), neighbor_pos.x, neighbor_pos.y));
				}

				//如果最终坐标依然无法到达 就跳出
				if (arr_range.find(neighbor_pos) < 0) return false;
				//pk::trace(pk::format("{}:移动到{},{}", pk::decode(pk::get_name(unit)), p_score_arr[0].pos.x, p_score_arr[0].pos.y));

				pk::action_info info = pk::action_info();
				info.type = 0;//1 攻击, 2 齐攻, 3 单挑, 4 战法, 5计略, 6 建造 7 修复
				info.move_pos = neighbor_pos;//即将要移动到的坐标，需要确保能移动到
				//info.target_pos = pk::point(2, 2);//要执行动作对象的坐标，如果攻击，就是攻击对象的坐标，建造，就是要建造建筑物的坐标
				//info.action_id = 计略_扰乱;//可以是tactics_id, facility_id, strategy_id，根据info.type决定，如攻击，齐攻，单挑就是-1，如战法，就是战法id，计略，就是计略id，建造，就是要建造设施的id(修复时不需要id)
				//info.score = 10000;//对应动作的打分，所以可以建一个数组，储存多个action_info,最后比较得分来随机选择得分高的action_info去执行
				//info.chance = 50;//执行对应动作的成功率，如计略就是计略成功率，战法就是战法成功率，单挑就是单挑成功率
				//info.chance = cast<pk::func206_t>(pk::get_func(206))(unit, info.move_pos, info.target_pos, 计略_扰乱).first;//执行妙计_大混乱成功率的写法
				if (调试模式.v)pk::trace(pk::format("{}:移动到{},{},部队状态{}", pk::decode(pk::get_name(unit)), p_score_arr[0].pos.x, p_score_arr[0].pos.y, unit.status));
				pk::get_movable_pos(unit, true);
				pk::conduct_action(info);
				return true;
			}

			return false;
		}

				// ********************************************************** 搜索可攻击敌方建筑的函数*************************************************
		void get_list_candidate_building(pk::unit @unit)
		{
			// 初始化列表
			if (!pk::is_alive(unit))
				return;
			list_candidate_building.clear();
			int weapon_id = unit.weapon;
			int weapon_type = get_weapon_type(weapon_id); // 0:剑, 1:战斗, 2:冲车, 3:井阑, 4:水军 5:大船

			pk::array<pk::point> arr_t = pk::get_movable_pos(unit);
			for (int j = 0; j < int(arr_t.length); j++)
			{
				pk::hex @hex = pk::get_hex(arr_t[j]);
				if (hex.has_building)
				{
					pk::building @target_building = pk::get_building(arr_t[j]);
					if (target_building !is null and pk::is_alive(target_building)
						and (pk::is_enemy(unit, target_building)
							or (target_building.get_force_id() == -1 and target_building.facility <= 设施_港口)))
					{
						list_candidate_building.add(target_building); // 如果敌方建筑可攻击，则添加到列表中
					}
				}
			}
		}

		// ********************************************************** 搜索可攻击敌方部队的函数*************************************************

		void get_list_candidate_unit(pk::unit @unit)
		{
			// 初始化列表
			if (!pk::is_alive(unit))
				return;
			list_candidate_unit.clear();
			int weapon_id = unit.weapon;
			int weapon_type = get_weapon_type(weapon_id); // 0:剑, 1:战斗, 2:冲车, 3:攻城其他, 4:水军

			// 冲车不作为搜索目标
			if (weapon_id == 兵器_冲车)
				return;

			pk::array<pk::point> arr_t = pk::get_movable_pos(unit);
			for (int j = 0; j < int(arr_t.length); j++)
			{
				pk::point pos = arr_t[j];
				pk::hex @hex = pk::get_hex(pos);

				pk::unit @target_unit = pk::get_unit(arr_t[j]);
				if (!hex.has_building and target_unit !is null and pk::is_alive(target_unit) and pk::is_enemy(unit, target_unit))
				{
					list_candidate_unit.add(target_unit); // 如果敌方部队可攻击，则添加到列表中

				}
			}
		}

	 // ********************************************************** 搜索附近我方部队 用于给异常部队复制任务*************************************************
		void get_list_ally_unit(pk::unit @unit)
		{
			// 初始化列表
			if (!pk::is_alive(unit))
				return;
			list_ally_unit.clear();
			int weapon_id = unit.weapon;
			int weapon_type = get_weapon_type(weapon_id); // 0:剑, 1:战斗, 2:冲车, 3:攻城其他, 4:水军


			pk::array<pk::point> arr_t = pk::range(unit.pos, 1, 6);
			for (int i = 0; i < int(arr_t.length); i++)
			{
				pk::point pos = arr_t[i];
				pk::hex @hex = pk::get_hex(pos);

				pk::unit @target_unit = pk::get_unit(arr_t[i]);
				if (!hex.has_building and target_unit !is null and pk::is_alive(target_unit) and unit.get_force_id() == target_unit.get_force_id() and unit.type == 部队类型_战斗)
				{
					if (unit.order == 部队任务_撤退) continue;
					if (unit.order == 部队任务_拦截 or unit.order == 部队任务_攻击 or unit.order == 部队任务_征服 or unit.order == 部队任务_攻城 or unit.order == 部队任务_移动)
						list_ally_unit.add(target_unit); // 如果我方部队战斗中，则添加到列表中

				}
			}
		}

		// 获取部队的攻击最小和最大射程
		pk::int_int get_atk_range(pk::unit @unit)
		{
			pk::int_int atk_range = pk::int_int(1, 1);
			if (!pk::is_alive(unit) or unit.weapon == 兵器_剑)
				return atk_range;
			int weapon_id = unit.weapon;
			if (weapon_id < 0)
				pk::trace(pk::format("{},兵装{},", pk::decode(pk::get_name(unit), weapon_id)));

			pk::equipment @epq = pk::get_equipment(unit.weapon);
			string eqp_name = pk::decode(pk::get_name(epq));
			string info = pk::format("{}", eqp_name);
			int min_range = 5;
			int max_range = 1;
			for (int j = 0; j < 可用战法_末; j++)
			{
				if (epq.tactics[j])
				{
					pk::tactics @tts = pk::get_tactics(j);
					string tts_name = pk::decode(pk::get_name(tts));
					info += pk::format(" {}({},{})", tts_name, tts.min_range, tts.max_range);
					min_range = pk::min(min_range, tts.min_range);
					max_range = pk::max(max_range, tts.max_range);
				}
			}
			if (weapon_id == 兵器_弩 and unit.has_tech(技巧_强弩))
				max_range += 1;
			if (weapon_id == 兵器_战马 and (unit.has_tech(技巧_骑射) or unit.has_skill(特技_白马)))
				max_range = pk::max(2, max_range);
			if ((weapon_id == 兵器_井阑 or weapon_id == 兵器_投石) and unit.has_skill(特技_射程))
				max_range += 1;
			atk_range = pk::int_int(min_range, max_range);
			return atk_range;
		}

		// 获取部队的最大攻击射程函数
		int get_max_atk_range(pk::unit @unit)
		{
			if (!pk::is_alive(unit))
				return 1;
			int weapon_id = unit.weapon;
			int max_range = 0;
			if (weapon_id == 兵器_弩)
				max_range = (unit.has_tech(技巧_强弩)) ? 3 : 2;
			else if (weapon_id == 兵器_战马)
				max_range = (unit.has_tech(技巧_骑射) or unit.has_skill(特技_白马)) ? 2 : 1;
			else if (weapon_id == 兵器_井阑)
				max_range = ((unit.has_skill(特技_射程)) ? 1 : 0) + (pk::get_tactics(战法_攻城火矢).max_range);
			else if (weapon_id == 兵器_投石)
				max_range = ((unit.has_skill(特技_射程)) ? 1 : 0) + (pk::get_tactics(战法_攻城投石).max_range);
			else if (weapon_id >= 兵器_走舸)
				max_range = 2;
			else
				max_range = 1;
			return max_range;
		}


		int get_weapon_type(int weapon_id)
		{
			int weapon_type = -1;
			if (weapon_id == 兵器_剑)
				weapon_type = 0;
			else if (weapon_id >= 兵器_枪 and weapon_id <= 兵器_战马)
				weapon_type = 1;
			else if (weapon_id == 兵器_冲车 or weapon_id == 兵器_木兽)
				weapon_type = 2;
			else if (weapon_id >= 兵器_井阑 or weapon_id == 兵器_投石)
				weapon_type = 3;
			else if (weapon_id == 兵器_走舸)
				weapon_type = 4;
			else if (weapon_id > 兵器_走舸)
				weapon_type = 5;

			return weapon_type;
		}


		pk::point get_movable_empty_pos(pk::unit @unit, pk::point pos, int distance_min, int distance_max)
		{
			array<pk::point> range_pos_arr = pk::range(pos, distance_min, distance_max);
			pk::array<pk::point> move_arr_range = pk::get_movable_pos(unit);

			for (int arr_index = 0; arr_index < int(range_pos_arr.length); arr_index++)
			{
				pk::point range_pos = range_pos_arr[arr_index];
				if (!pk::is_valid_pos(range_pos))
					continue;

				//如果不可行动到,就放弃
				if (move_arr_range.find(range_pos) < 0)
					continue;


				pk::hex @hex = pk::get_hex(range_pos);
				if (hex.has_building)
					continue;
				if (hex.has_unit)
					continue;

				int terrain_id = hex.terrain;
				if (!pk::is_valid_terrain_id(terrain_id))
					continue;
				if (!pk::is_enabled_terrain(terrain_id))
					continue;

				return range_pos;
			}

			return pk::point(-1, -1);
		}

		pk::point get_empty_pos(pk::point pos, int distance_min, int distance_max)
		{
			array<pk::point> range_pos_arr = pk::range(pos, distance_min, distance_max);
			for (int arr_index = 0; arr_index < int(range_pos_arr.length); arr_index++)
			{
				pk::point range_pos = range_pos_arr[arr_index];
				if (!pk::is_valid_pos(range_pos))
					continue;

				pk::hex @hex = pk::get_hex(range_pos);
				if (hex.has_building)
					continue;
				if (hex.has_unit)
					continue;

				int terrain_id = hex.terrain;
				if (!pk::is_valid_terrain_id(terrain_id))
					continue;
				if (!pk::is_enabled_terrain(terrain_id))
					continue;

				return range_pos;
			}

			return pk::point(-1, -1);
		}

	}
	Main main;
}